home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-11-28 | 3.5 KB | 98 lines | [TEXT/MACA] |
- {
- This Pascal fragment illustrates how to calculate an XMODEM/YMODEM
- type Cyclic Redundancy Check (CRC) with minimal performance overhead,
- namely on a one-operation-per-byte basis. It is nearly as fast as
- the old arithmetic checksum. Communications programmers who don't
- know the "256 word table" trick will want to download this file so
- they can improve their code's performance. Also curiosity-seekers
- and for general education.
-
- A SHORT HISTORY
-
- The contributor has recently (11/25/87) written an XMODEM/YMODEM
- program in VAX Pascal. I planned to use the VAX CRC instruction
- but discovered it computed CRC's with the least-significant-bit of
- each byte going in first, while the XMODEM/YMODEM CRC wants the
- most-significant bit to be inserted first. The table-driven
- nature of the VAX instruction, and dissatisfaction with the overhead
- of bitwise computation, led me to discover the algorithm shown here.
-
- This has been tested by using an incorrect polynomial, which of course
- leads to a hard error. It has NOT been tested by injection of line
- errors (direct link used on the system on which it was developed, and
- no electriv drill handy). It is free and public domain.
-
- { some type declarations to keep VAX Pascal happy.}
-
- TYPE $UBYTE = [BYTE]0..255; $UWORD = [WORD]0..65535;
-
- {the following type aCRC is dependent on VAX storage allocation,
- and will be different on othe machines, particularly 16-bit ones.}
-
- aCRC = PACKED RECORD CASE INTEGER OF
- 1: (crc32 : UNSIGNED);
- 2: (crc16,hi16 : $UWORD);
- 3: (lsbyte,nlsbyte,nmsbyte,msbyte : $UBYTE);
- END;
-
- VAR crcTab : ARRAY [0..255] OF $UWORD; {global var, 16-bit entries}
-
-
- FUNCTION CRC(Buffer:PACKED ARRAY [1..1026] OF CHAR; Cnt:INTEGER):$UWORD;
-
- {this function computes and returns the 16-bit CRC of the first (Cnt)
- bytes in Buffer. For XMODEM/YMODEM transmission, it would be called
- with Cnt=128 or 1024. For reception, it would be called with Cnt=
- 130 or 1026. (Including the CRC itself in the calculation should
- "cancel" the accumulation up to that point, and the returned value
- is 0 if all is well.) The SOH/STX and the two record number bytes
- are not included in the CRC, and it's assumed they went somewhere
- else than in Buffer.
-
- UXOR is a VAX Pascal function that does a 32-bit Exclusive OR
- and returns an "unsigned" value.
- UINT is a VAX Pascal type transfer function that returns "UNSIGNED".
- ORD is a Pascal type transfer function that returns "INTEGER"
-
- In other words, UINT and ORD don't do anything useful...
- }
- VAR i:INTEGER; compCRC:aCRC;
- BEGIN
- WITH compCRC DO BEGIN
-
- crc32:=0;
-
- FOR i:=1 to Cnt DO crc32:=
- UXOR( lsbyte*256, crcTab[ ORD( UXOR( nlsbyte, UINT( Buffer[i])))]);
-
- CRC:=crc16;
- END {WITH};
- END;
-
- {in plainer terms: for each byte in Buffer, we compute a new 16-bit
- CRC as
-
- new CRC:=(oldCRC lo byte shifted left 8 bits, with 0's coming in)
- XOR
- crcTab[ (old CRC hi byte) XOR (the byte from Buffer) ]
-
- where the contents of crcTab are computed at program startup by the
- following subroutine:
- }
-
-
- PROCEDURE initCRCTab;
- VAR theCRC: aCRC; i,j:INTEGER;
- BEGIN
- WITH theCRC DO
- FOR i:=0 TO 255 DO BEGIN {fill up the table}
- crc32:=i*256; {index value shifted 8 right}
- FOR j:=1 to 8 DO BEGIN {test each of the 8 hi bits}
- crc32:=crc32+crc32; {left shift all 16 by 1}
- IF hi16>0 THEN {and if the bit shifted out is 1}
- crc32:= UXOR(crc16,%X'1021'); {then XOR in the polynomial}
- END {FOR j}; {for all 8}
- crcTab[i]:=crc16; {put the result in the table}
- END {FOR i};
- END;